﻿/** \file
* \par Subversion URL:
* \$URL: http://planar-rendering.googlecode.com/svn/trunk/frontend/src/OrthTarget.cs $
* \version \$Rev: 80 $
* \date    \$Date: 2009-04-20 10:18:23 +0000 (Mon, 20 Apr 2009) $
*/

using System;

namespace Frontend
{
	/// <summary>
	/// Target to render orthagonal projections and display them in-program.
	/// </summary>
	class OrthTarget : Target
	{
		/// <summary>
		/// The raw image data. Three dimensions by three rendering methods by
		/// the resolution of each dimension.
		/// </summary>
		public int[][][] images = new int[3][][];

		/// <summary>The x spatial range.</summary>
		Range xr;
		/// <summary>The y spatial range.</summary>
		Range yr;
		/// <summary>The z spatial range.</summary>
		Range zr;

		/// <summary>
		/// The constructor.
		/// </summary>
		/// <param name="genInit">The associated generator.</param>
		public OrthTarget(Generator genInit) :
			base(genInit)
		{
		}

		/// <summary>
		/// Begin generation. Allocates the image data.
		/// </summary>
		public override void Begin()
		{
			base.Begin();

			int nvars = gen.varranges.Count;

			for (int d = 0; d < 3; d++)
			{
				images[d] = new int[3][];
				int d1 = (d + 1) % 3;
				int d2 = (d + 2) % 3;
				int dsize = gen.spatialranges[d1].res * gen.spatialranges[d2].res;
				for (int m = 0; m < 3; m++)
					images[d][m] = new int[dsize];
				for (int i = 0; i < dsize; i++)
					images[d][0][i] = gen.spatialranges[d].res;
			}

			zr = gen.spatialranges[0];
			yr = gen.spatialranges[1];
			xr = gen.spatialranges[2];
		}

		/// <summary>
		/// End generation. Formats the image data.
		/// </summary>
		public override void End()
		{
			for (int d = 0; d < 3; d++)
			{
				int d1 = (d + 1) % 3;
				int d2 = (d + 2) % 3;
				int index = 0;
				int dres = gen.spatialranges[d].res;
				int[][] dimage = images[d];
				for (int iy = 0; iy < gen.spatialranges[d1].res; iy++)
				{
					for (int ix = 0; ix < gen.spatialranges[d2].res; ix++, index++)
					{
						dimage[0][index] = dres - dimage[0][index];
						for (int m = 0; m < 3; m++)
							dimage[m][index] = PixelValue(dimage[m][index] / (double)dres);
					}
				}
			}

			Orth orth = new Orth();
			orth.ShowDialog();
		}

		/// <summary>
		/// Process the row data. Writes to the image data.
		/// </summary>
		/// <param name="threadno">The thread number.</param>
		public override void Write(int threadno)
		{
			int zres = zr.res, z = zr.resindex[threadno];
			int yres = yr.res, y = yr.resindex[threadno];
			int xres = xr.res;
			int[] indices = new int[3]
			{
				y*xres,/*+x*/	// z variant, y outer, x inner
				/*x*zres+*/z,	// y variant, x outer, z inner
				z*yres+y		// x variant, z outer, y inner
			};
			int[] axes = new int[3] { z, y, 0 };
			byte[] row = gen.row[threadno];
			for (; axes[2] < xres; axes[2]++)
			{
				if (row[axes[2]] != 0)
				{
					for (int d = 0; d < 3; d++)
					{
						int index = indices[d];
						int[][] dimage = images[d];
						if (dimage[0][index] > axes[d]) dimage[0][index] = axes[d];
						if (dimage[1][index] < axes[d]) dimage[1][index] = axes[d];
						dimage[2][index]++;
					}
				}
				indices[0]++;
				indices[1] += zres;
			}
		}

		/// <summary>
		/// Turns a double into a pixel value.
		/// </summary>
		/// <param name="val">The value to convert, from 0 to 1.</param>
		/// <returns>An RGB pixel integer.</returns>
		static int PixelValue(double val)
		{
			if (val < 0.5)
				return (int)(255 * val / 0.5) << 16;
			int lum = (int)((val - 0.5) / 0.5 * 255);
			return 0xFF00000 | lum | (lum << 8);
		}
	}
}
